﻿using System;

namespace Core
{
    public interface IMessageHandler
    {
        void OnReceive(ISession session, object message, byte rpcID);
        Type GetRequestType();
    }

    [AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = true)]
    public class MessageHandlerAttribute : Attribute
    {

    }

    [MessageHandler]
    public abstract class MessageHandler<Request, Response> : IMessageHandler
        where Request : class, IRequestMessage
        where Response : class, IResponseMessage
    {
        protected abstract ETTask Handle(ISession session, Request request, Response response, Func<ETTask> completed);

        public Type GetRequestType()
        {
            return typeof(Request);
        }

        public async void OnReceive(ISession session, object message, byte rpcID)
        {
            var request = message as Request;
            if (request == null)
            {
                new CoreTip(TipLevel.Error, $"message(type:{message.GetType()}) != request(type{GetRequestType()})").Publish();
            }
            else
            {
                var response = Activator.CreateInstance(typeof(Response)) as Response;
                var completed = new Func<ETTask>(async () =>
                {
                    ((Session)session).SendMessage(response, rpcID);
                    await ETTask.CompletedTask;
                });

                try
                {
                    await Handle(session, request, response, completed);
                }
                catch(Exception e)
                {
                    new CoreTip(TipLevel.Error, e.ToString()).Publish();
                    response.error = 1;
                    await completed();
                }
            }
        }
    }

    [MessageHandler]
    public abstract class PushMessageHandler<Push> : IMessageHandler 
        where Push : class, IPushMessage
    {
        protected abstract ETTask Handle(ISession session, Push push, Func<ETTask> completed);

        public Type GetRequestType()
        {
            return typeof(Push);
        }

        public async void OnReceive(ISession session, object message, byte rpcID)
        {
            var push = message as Push;
            if (push == null)
            {
                new CoreTip(TipLevel.Error, $"message(type:{message.GetType()}) != request(type{GetRequestType()})").Publish();
            }
            else
            {
                var completed = new Func<ETTask>(async () =>
                {
                    await ETTask.CompletedTask;
                });

                try
                {
                    await Handle(session, push, completed);
                }
                catch (Exception e)
                {
                    new CoreTip(TipLevel.Error, e.ToString()).Publish();
                }
            }
        }
    }
}
